﻿using System;

namespace Lesson4_构造函数与析构函数
{
    class Person
    {
        public string name;
        public int age;
        public string homeAddress;

        #region 一 构造函数
        //基本概念
        //实例化对象时 需要调用构造函数初始化
        //如果不去申明 那么默认存在一个无参的构造函数
        //如果申明 那么默认的无参构造函数会消失(在结构体中 就算我们主动申明了一个构造函数 该无参构造函数也不会消失)

        //构造函数的写法
        // 1.没有返回值
        // 2.函数名与类名相同
        // 3.构造函数可以重载
        // 4.一般使用public修饰
        // 5.this关键字表示该类中的成员变量 使用this关键字可以将成员变量与传入的参数进行区分
        public Person(string name, int age)
        {
            this.name = name;
            this.age = age;
        }

        public Person(int age)
        {
            name = "";
            this.age = age;
        }

        //类中允许自己申明无参构造函数
        //结构体中不允许
        public Person()
        {
            name = "LiberTy";
            age = 18;
        }

        #region 构造函数特殊写法
        // :this(参数1, 参数2, ......)
        //这样写的作用是 在执行函数内代码前 先调用this后括号内参数对应的构造函数
        //参数可以是前面传入的参数 如下面的age和name 也可以直接传入常量 只要数据类型匹配即可
        public Person(int age, string name, string homeAddress):this()
        {
            //name和age的初始化可以直接调用前面的构造函数 节省代码量
            this.homeAddress = homeAddress;
            Console.WriteLine(name + age + homeAddress);
        }
        #endregion
        #endregion

        #region 二 析构函数
        //当引用类型的堆内存垃圾被回收时 被调用
        //如 我们先实例化一个类 Person p = new Person(); 这时会在堆中为它分配一个空间
        //   再将这个类赋为空值 p = null; 这时我们先前在堆内存中分配的空间就不会有任何引用 成为堆内存垃圾
        //基本不使用 C#有垃圾自动回收机制
        ~Person()
        {

        }
        #endregion

        #region 三 垃圾回收机制
        //垃圾回收,英文简写GC (Garbage Collector)
        //垃圾回收的过程是在遍历堆上动态分配的所有对象
        //通过识别它们是否被引用来确定哪些对象是垃圾，哪些对象仍要被使用
        //垃圾就是没有被任何引用类型的变量，对象引用的内容 需要被回收释放

        //垃圾回收有很多种算法，比如
        //引用计数（Reference Counting）
        //标记清除（Mark Sweep）
        //标记整理（Mark Compact）
        //复制集合（Copy Collection）

        //GC只负责堆(Heap)上的垃圾回收
        //引用类型的值都存放在堆中 它的分配与释放都通过垃圾回收机制来进行管理

        //栈(Stack)上的内存由系统自动管理
        //值类型在栈中分配 有自己的生命周期 不需要进行管理 会自动分配和释放

        //C#中内存回收机制的大致原理
        //0代内存 1代内存 2代内存
        //代的概念:
        //代是垃圾回收机制的一种算法(分代算法)
        //新分配的对象都会被分配在0代内存中
        //每次分配都可能会触发垃圾回收机制以释放内存(0代内存满时)

        //在一次内存回收过程开始时 垃圾回收器会认为堆中全是垃圾 进行如下两步
        // 1.标记对象: 从根（静态字段 方法参数）开始检查引用对象 标记有引用的对象
        //   标记后为可达对象 未标记为不可达对象 不可达对象被认为是垃圾
        // 2.搬迁对象压缩堆： 释放垃圾后 将未被释放的对象移入下一代内存 并将它们进行压缩

        //1代内存垃圾回收时 0代内存会一同进行释放
        //2代内存垃圾回收时 0 1代内存会一同进行释放

        //大对象总被认为是存在2代内存 目的是减少性能损耗 提高性能
        //不会对大对象进行搬迁压缩 85000字节（83kb）以上的对象为大对象

        #endregion
    }

    class Program
    {
        static void Main(string[] args)
        {
            string name = "hhh";
            int age = 18;
            string homeAddress = "比奇堡";

            //构造函数仅能在实例化对象时被调用
            //用.调用和下面的写法都是不被允许的
            //Person p;
            //p = Person(name, age);
            //下面是正确使用方法
            Person p = new Person(age);
            //构造函数特殊写法使用
            Person p2 = new Person(age, name, homeAddress);

            // *手动进行垃圾回收
            //虽然C#有自动的垃圾回收机制 但我们有时还是会主动进行垃圾回收操作
            //这是因为GC耗时较长 在游戏运行过程中进行GC可能会导致卡顿
            //所以可以在游戏Loading时手动进行GC 以减少卡顿情况
            GC.Collect();
        }
    }
    
}